home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / minix / mkproto.zoo / mkproto.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-09-07  |  12.5 KB  |  658 lines

  1. /* Program to extract function declarations from C source code */
  2. /* Written by Eric R. Smith and placed in the public domain    */
  3. /* Thanks are due to Jwahar R. Bammi for fixing several bugs   */
  4. /* and providing the Unix makefiles.                           */
  5.  
  6. #if defined(__STDC__) && !defined(minix)
  7. #include <stddef.h>
  8. #include <stdlib.h>
  9. #else
  10. #define EXIT_SUCCESS  0
  11. #define EXIT_FAILURE  1
  12. extern char *malloc();
  13. #endif
  14.  
  15. #include <stdio.h>
  16. #include <ctype.h>
  17. #include <string.h>
  18.  
  19. /*#define DEBUG(s) (fputs(s, stderr)) /* */
  20. #define DEBUG(s) /* */
  21.  
  22. #define ISCSYM(x) ((x) > 0 && (isalnum(x) || (x) == '_'))
  23. #define ABORTED ( (Word *) -1 )
  24. #define MAXPARAM 20         /* max. number of parameters to a function */
  25. #define NEWBUFSIZ (20480*sizeof(char)) /* new buffer size */
  26.  
  27. int inquote = 0;        /* in a quote?? */
  28. int newline_seen = 1;        /* are we at the start of a line */
  29. long linenum  = 1L;        /* line number in current file */
  30. int dostatic = 0;        /* do static functions? */
  31. int donum    = 0;        /* print line numbers? */
  32. int dohead   = 1;        /* do file headers? */
  33. int docond   = 1;        /* conditionalize for non-ANSI compilers? */
  34. int glastc   = ' ';        /* last char. seen by getsym() */
  35.  
  36. typedef struct word {
  37.     struct word *next;
  38.     char   string[1];
  39. } Word;
  40.  
  41. #include "mkproto.h"
  42.  
  43. /*
  44.  * Routines for manipulating lists of words.
  45.  */
  46.  
  47. Word *word_alloc(s)
  48.     char *s;
  49. {
  50.     Word *w;
  51.  
  52.     w = (Word *) malloc(sizeof(Word) + strlen(s) + 1); /* ++jrb */
  53.     strcpy(w->string, s);
  54.     w->next = NULL;
  55.     return w;
  56. }
  57.  
  58. void word_free(w)
  59.     Word *w;
  60. {
  61.     Word *oldw;
  62.     while (w) {
  63.         oldw = w;
  64.         w = w->next;
  65.         free(oldw);
  66.     }
  67. }
  68.  
  69. /* return the length of a list; empty words are not counted */
  70. int
  71. List_len(w)
  72.     Word *w;
  73. {
  74.     int count = 0;
  75.  
  76.     while (w) {
  77.         if (*w->string) count++;
  78.         w = w->next;
  79.     }
  80.     return count;
  81. }
  82.  
  83. /* Append two lists, and return the result */
  84.  
  85. Word *word_append(w1, w2)
  86.     Word *w1, *w2;
  87. {
  88.     Word *r, *w;
  89.  
  90.     r = w = word_alloc("");
  91.  
  92.     while (w1) {
  93.         w->next = word_alloc(w1->string);
  94.         w = w->next;
  95.         w1 = w1->next;
  96.     }
  97.     while (w2) {
  98.         w->next = word_alloc(w2->string);
  99.         w = w->next;
  100.         w2 = w2->next;
  101.     }
  102.  
  103.     return r;
  104. }
  105.     
  106. /* see if the last entry in w2 is in w1 */
  107.  
  108. int
  109. foundin(w1, w2)
  110.     Word *w1, *w2;
  111. {
  112.     while (w2->next)
  113.         w2 = w2->next;
  114.  
  115.     while (w1) {
  116.         if (!strcmp(w1->string, w2->string))
  117.             return 1;
  118.         w1 = w1->next;
  119.     }
  120.     return 0;
  121. }
  122.  
  123. /* add the string s to the given list of words */
  124.  
  125. void addword(w, s)
  126.     Word *w; char *s;
  127. {
  128.     while (w->next) w = w->next;
  129.     w->next = word_alloc(s);
  130. }
  131.  
  132. /* given a list representing a type and a variable name, extract just
  133.  * the base type, e.g. "struct word *x" would yield "struct word"
  134.  */
  135.  
  136. Word *typelist(p)
  137.     Word *p;
  138. {
  139.     Word *w, *r;
  140.  
  141.     r = w = word_alloc("");
  142.     while (p && p->next) {
  143.         if (p->string[0] && !ISCSYM(p->string[0]))
  144.             break;
  145.         w->next = word_alloc(p->string);
  146.         w = w->next;
  147.         p = p->next;
  148.     }
  149.     return r;
  150. }
  151.  
  152. /* typefixhack: promote formal parameters of type "char", "unsigned char",
  153.    "short", or "unsigned short" to "int".
  154. */
  155.  
  156. void typefixhack(w)
  157.     Word *w;
  158. {
  159.     Word *oldw = 0;
  160.  
  161.     while (w) {
  162.         if (*w->string) {
  163.             if ( (!strcmp(w->string, "char") ||
  164.                   !strcmp(w->string, "short") )
  165.                 && (List_len(w->next) < 2) )
  166.             {
  167.                 if (oldw && !strcmp(oldw->string, "unsigned")) {
  168.                     oldw->next = w->next;
  169.                     free(w);
  170.                     w = oldw;
  171.                 }
  172.                 strcpy(w->string, "int");
  173.             }
  174.         }
  175.         w = w->next;
  176.     }
  177. }
  178.  
  179. /* read a character: if it's a newline, increment the line count */
  180.  
  181. #ifdef __GNUC__    /* ++jrb */
  182. inline
  183. #endif
  184. int ngetc(f)
  185.     FILE *f;
  186. {
  187.     int c;
  188.  
  189.     c = getc(f);
  190.     if (c == '\n') linenum++;
  191.  
  192.     return c;
  193. }
  194.  
  195. /* read the next character from the file. If the character is '\' then
  196.  * read and skip the next character. Any comment sequence is converted
  197.  * to a blank.
  198.  */
  199.  
  200. int fnextch(f)
  201.     FILE *f;
  202. {
  203.     int c, lastc, incomment;
  204.  
  205.     c = ngetc(f);
  206.     while (c == '\\') {
  207. DEBUG("fnextch: in backslash loop\n");
  208.         c = ngetc(f);    /* skip a character */
  209.         c = ngetc(f);
  210.     }
  211.     if (c == '/' && !inquote) {
  212.         c = ngetc(f);
  213.         if (c == '*') {
  214.             incomment = 1;
  215.             c = ' ';
  216. DEBUG("fnextch: comment seen\n");
  217.             while (incomment) {
  218.                 lastc = c;
  219.                 c = ngetc(f);
  220.                 if (lastc == '*' && c == '/')
  221.                     incomment = 0;
  222.                 else if (c < 0)
  223.                     return c;
  224.             }
  225.             return fnextch(f);
  226.         }
  227.         else {
  228.             if (c == '\n') linenum--;
  229.             ungetc(c, f);
  230.             return '/';
  231.         }
  232.     }
  233.     return c;
  234. }
  235.  
  236.  
  237. /* Get the next "interesting" character. Comments are skipped, and strings
  238.  * are converted to "0". Also, if a line starts with "#" it is skipped.
  239.  */
  240.  
  241. int nextch(f)
  242.     FILE *f;
  243. {
  244.     int c;
  245.  
  246.     c = fnextch(f);
  247.     if (newline_seen && c == '#') {
  248.         do {
  249.             c = fnextch(f);
  250.         } while (c >= 0 && c != '\n');
  251.         if (c < 0)
  252.             return c;
  253.     }
  254.     newline_seen = (c == '\n');
  255.  
  256.     if (c == '\'' || c == '\"') {
  257. DEBUG("nextch: in a quote\n");
  258.         inquote = c;
  259.         while ( (c = fnextch(f)) >= 0 ) {
  260.             if (c == inquote) {
  261.                 inquote = 0;
  262. DEBUG("nextch: out of quote\n");
  263.                 return '0';
  264.             }
  265.         }
  266. DEBUG("nextch: EOF in a quote\n");
  267.     }
  268.     return c;
  269. }
  270.  
  271. /*
  272.  * Get the next symbol from the file, skipping blanks.
  273.  * Return 0 if OK, -1 for EOF.
  274.  * Also collapses everything between { and }
  275.  */
  276.  
  277. int
  278. getsym(buf, f)
  279.     char *buf; FILE *f;
  280. {
  281.     register int c;
  282.     int inbrack = 0;
  283.  
  284. DEBUG("in getsym\n");
  285.     c = glastc;
  286.     while ((c > 0) && isspace(c)) {
  287.         c = nextch(f);
  288.     }
  289. DEBUG("getsym: spaces skipped\n");
  290.     if (c < 0) {
  291. DEBUG("EOF read in getsym\n");
  292.         return -1;
  293.     }
  294.     if (c == '{') {
  295.         inbrack = 1;
  296. DEBUG("getsym: in bracket\n");
  297.         while (inbrack) {
  298.             c = nextch(f);
  299.             if (c < 0) {
  300. DEBUG("getsym: EOF seen in bracket loop\n");
  301.                 glastc = c;
  302.                 return c;
  303.             }
  304.             if (c == '{') inbrack++;
  305.             else if (c == '}') inbrack--;
  306.         }
  307.         strcpy(buf, "{}");
  308.         glastc = nextch(f);
  309. DEBUG("getsym: out of in bracket loop\n");
  310.         return 0;
  311.     }
  312.     if (!ISCSYM(c)) {
  313.         *buf++ = c;
  314.         *buf = 0;
  315.         glastc = nextch(f);
  316. DEBUG("getsym: returning special symbol\n");
  317.         return 0;
  318.     }
  319.     while (ISCSYM(c)) {
  320.         *buf++ = c;
  321.         c = nextch(f);
  322.     }
  323.     *buf = 0;
  324.     glastc = c;
  325. DEBUG("getsym: returning word\n");
  326.     return 0;
  327. }
  328.  
  329. /*
  330.  * skipit: skip until a ";" or the end of a function declaration is seen
  331.  */
  332. int skipit(buf, f)
  333.     char *buf;
  334.     FILE *f;
  335. {
  336.     int i;
  337.  
  338.     do {
  339. DEBUG("in skipit loop\n");
  340.         i = getsym(buf, f);
  341.         if (i < 0) return i;
  342.     } while (*buf != ';' && *buf != '{');
  343.  
  344.     return 0;
  345. }
  346.  
  347. /*
  348.  * Get a parameter list; when this is called the next symbol in line
  349.  * should be the first thing in the list.
  350.  */
  351.  
  352. Word *getparamlist(f)
  353.     FILE *f;
  354. {
  355.     static Word *pname[MAXPARAM]; /* parameter names */
  356.     Word    *tlist,        /* type name */
  357.         *plist;        /* temporary */
  358.     int      np = 0;        /* number of parameters */
  359.     int      typed[MAXPARAM];  /* parameter has been given a type */
  360.     int    tlistdone;    /* finished finding the type name */
  361.     int    sawsomething;
  362.     int      i;
  363.     int    inparen = 0;
  364.     char buf[80];
  365.  
  366. DEBUG("in getparamlist\n");
  367.     for (i = 0; i < MAXPARAM; i++)
  368.         typed[i] = 0;
  369.  
  370.     plist = word_alloc("");
  371.  
  372. /* first, get the stuff inside brackets (if anything) */
  373.  
  374.     sawsomething = 0;    /* gets set nonzero when we see an arg */
  375.     for (;;) {
  376.         if (getsym(buf, f) < 0) return NULL;
  377.         if (*buf == ')' && (--inparen < 0)) {
  378.             if (sawsomething) {    /* if we've seen an arg */
  379.                 pname[np] = plist;
  380.                 plist = word_alloc("");
  381.                 np++;
  382.             }
  383.             break;
  384.         }
  385.         if (*buf == ';') {    /* something weird */
  386.             return ABORTED;
  387.         }
  388.         sawsomething = 1;    /* there's something in the arg. list */
  389.         if (*buf == ',' && inparen == 0) {
  390.             pname[np] = plist;
  391.             plist = word_alloc("");
  392.             np++;
  393.         }
  394.         else {
  395.             addword(plist, buf);
  396.             if (*buf == '(') inparen++;
  397.         }
  398.     }
  399.  
  400. /* next, get the declarations after the function header */
  401.  
  402.     inparen = 0;
  403.  
  404.     tlist = word_alloc("");
  405.     plist = word_alloc("");
  406.     tlistdone = 0;
  407.     sawsomething = 0;
  408.     for(;;) {
  409.         if (getsym(buf, f) < 0) return NULL;
  410.  
  411. /* handle a list like "int x,y,z" */
  412.         if (*buf == ',' && !inparen) {
  413.             if (!sawsomething)
  414.                 return NULL;
  415.             for (i = 0; i < np; i++) {
  416.                 if (!typed[i] && foundin(plist, pname[i])) {
  417.                     typed[i] = 1;
  418.                     word_free(pname[i]);
  419.                     pname[i] = word_append(tlist, plist);
  420.                 /* promote types */
  421.                     typefixhack(pname[i]);
  422.                     break;
  423.                 }
  424.             }
  425.             if (!tlistdone) {
  426.                 tlist = typelist(plist);
  427.                 tlistdone = 1;
  428.             }
  429.             word_free(plist);
  430.             plist = word_alloc("");
  431.         }
  432. /* handle the end of a list */
  433.         else if (*buf == ';') {
  434.             if (!sawsomething)
  435.                 return ABORTED;
  436.             for (i = 0; i < np; i++) {
  437.                 if (!typed[i] && foundin(plist, pname[i])) {
  438.                     typed[i] = 1;
  439.                     word_free(pname[i]);
  440.                     pname[i] = word_append(tlist, plist);
  441.                     typefixhack(pname[i]);
  442.                     break;
  443.                 }
  444.             }
  445.             tlistdone = 0;
  446.             word_free(tlist); word_free(plist);
  447.             tlist = word_alloc("");
  448.             plist = word_alloc("");
  449.         }
  450. /* handle the  beginning of the function */
  451.         else if (!strcmp(buf, "{}")) break;
  452. /* otherwise, throw the word into the list (except for "register") */
  453.         else if (strcmp(buf, "register")) {
  454.             sawsomething = 1;
  455.             addword(plist, buf);
  456.             if (*buf == '(') inparen++;
  457.             if (*buf == ')') inparen--;
  458.         }
  459.     }
  460.  
  461. /* Now take the info we have and build a prototype list */
  462.  
  463. /* empty parameter list means "void" */
  464.     if (np == 0)
  465.         return word_alloc("void");
  466.  
  467.     plist = tlist = word_alloc("");
  468.     for (i = 0; i < np; i++) {
  469.  
  470. /* If no type provided, make it an "int" */
  471.         if ( !(pname[i]->next) ||
  472.        (!(pname[i]->next->next)&&strcmp(pname[i]->next->string, "void"))) {
  473.             addword(tlist, "int");
  474.         }
  475.         while (tlist->next) tlist = tlist->next;
  476.         tlist->next = pname[i];
  477.         if (i < np - 1)
  478.             addword(tlist, ", ");
  479.     }
  480.     return plist;
  481. }
  482.  
  483. /*
  484.  * emit a function declaration. The attributes and name of the function
  485.  * are in wlist; the parameters are in plist.
  486.  */
  487. void emit(wlist, plist, startline)
  488.     Word *wlist, *plist;
  489.     long  startline;
  490. {
  491.     Word *w;
  492.     int count = 0;
  493.  
  494. DEBUG("emit called\n");
  495.     if (donum)
  496.         printf("/*%8ld */ ", startline);
  497.  
  498.     for (w = wlist; w; w = w->next) {
  499.         if (w->string[0])
  500.             count ++;
  501.     }
  502.  
  503.     if (count < 2)
  504.         printf("int ");
  505.  
  506.     for (w = wlist; w; w = w->next) {
  507.         printf("%s", w->string);
  508.         if (ISCSYM(w->string[0]))
  509.             printf(" ");
  510.     }
  511.     if (docond)
  512.         printf("P((");
  513.     else
  514.         printf("( ");
  515.     for (w = plist; w; w = w->next) {
  516.         printf("%s", w->string);
  517.         if (ISCSYM(w->string[0]))
  518.             printf(" ");
  519.     }
  520.     if (docond)
  521.         printf("));\n");
  522.     else
  523.         printf(");\n");
  524. }
  525.  
  526. /*
  527.  * get all the function declarations
  528.  */
  529.  
  530. void getdecl(f)
  531.     FILE *f;
  532. {
  533.     Word *plist, *wlist = NULL;
  534.     char buf[80];
  535.     int sawsomething;
  536.     long startline;        /* line where declaration started */
  537.     int oktoprint;
  538. again:
  539.     word_free(wlist);
  540.     wlist = word_alloc("");
  541.     sawsomething = 0;
  542.     oktoprint = 1;
  543.  
  544.     for(;;) {
  545. DEBUG("main getdecl loop\n");
  546.         if (getsym(buf,f) < 0) {
  547. DEBUG("EOF in getdecl loop\n");
  548.              return;
  549.         }
  550. /* try to guess when a declaration is not an external function definition */
  551.         if (!strcmp(buf, ",") || !strcmp(buf, "{}") ||
  552.             !strcmp(buf, "=") || !strcmp(buf, "typedef") ||
  553.             !strcmp(buf, "extern")) {
  554.             skipit(buf, f);
  555.             goto again;
  556.         }
  557.         if (!dostatic && !strcmp(buf, "static")) {
  558.             oktoprint = 0;
  559.         }
  560. /* for the benefit of compilers that allow "inline" declarations */
  561.         if (!strcmp(buf, "inline") && !sawsomething)
  562.             continue;
  563.         if (!strcmp(buf, ";")) goto again;
  564.  
  565. /* A left parenthesis *might* indicate a function definition */
  566.         if (!strcmp(buf, "(")) {
  567.             startline = linenum;
  568.             if (!sawsomething || !(plist = getparamlist(f))) {
  569.                 skipit(buf, f);
  570.                 goto again;
  571.             }
  572.             if (plist == ABORTED)
  573.                 goto again;
  574.  
  575. /* It seems to have been what we wanted */
  576.             if (oktoprint)
  577.                 emit(wlist, plist, startline);
  578.             word_free(plist);
  579.             goto again;
  580.         }
  581.         addword(wlist, buf);
  582.         sawsomething = 1;
  583.     }
  584. }
  585.  
  586. void
  587. main(argc, argv)
  588. int argc; char **argv;
  589. {
  590.     FILE *f;
  591.     char *t, *iobuf;
  592.     extern void Usage();
  593.  
  594.     argv++; argc--;
  595.  
  596.     iobuf = malloc(NEWBUFSIZ);
  597.     while (*argv && **argv == '-') {
  598.         t = *argv++; --argc; t++;
  599.         while (*t) {
  600.             if (*t == 's')
  601.                 dostatic = 1;
  602.             else if (*t == 'n')
  603.                 donum = 1;
  604.             else if (*t == 'p')
  605.                 docond = 0;
  606.             else
  607.                 Usage();
  608.             t++;
  609.         }
  610.     }
  611.  
  612.     if (docond) {
  613.         printf("#ifdef __STDC__\n");
  614.         printf("# define\tP(s) s\n");
  615.         printf("#else\n");
  616.         printf("# define P(s) ()\n");
  617.         printf("#endif\n\n");
  618.     }
  619.     if (argc == 0)
  620.         getdecl(stdin);
  621.     else
  622.         while (argc > 0 && *argv) {
  623. DEBUG("trying a new file\n");
  624.             if (!(f = fopen(*argv, "r"))) {
  625.                 perror(*argv);
  626.                 exit(EXIT_FAILURE);
  627.             }
  628.             if (iobuf)
  629.                 setvbuf(f, iobuf, _IOFBF, NEWBUFSIZ);
  630.             if (dohead)
  631.                 printf("\n/* %s */\n", *argv);
  632.             linenum = 1;
  633.             newline_seen = 1;
  634.             glastc = ' ';
  635. DEBUG("calling getdecl\n");
  636.             getdecl(f);
  637. DEBUG("back from getdecl\n");
  638.             argc--; argv++;
  639.             fclose(f);
  640. DEBUG("back from fclose\n");
  641.         }
  642.     if (docond) {
  643.         printf("\n#undef P\n");    /* clean up namespace */
  644.     }
  645.     exit(EXIT_SUCCESS);
  646. }
  647.  
  648.  
  649. void Usage()
  650. {
  651.     fputs("Usage: mkproto [-n][-s][-p][files ...]\n",stderr);
  652.     fputs("   -n: put line numbers of declarations as comments\n",stderr);
  653.     fputs("   -s: include declarations for static functions\n", stderr);
  654.     fputs("   -p: don't make header files readable by non-ANSI compilers\n",
  655.           stderr);
  656.     exit(EXIT_FAILURE);
  657. }
  658.